package vn.smartoffice.promail.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import lombok.Getter;
import lombok.Setter;

import org.zkoss.bind.BindContext;
import org.zkoss.bind.BindUtils;
import org.zkoss.bind.annotation.BindingParam;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.bind.annotation.GlobalCommand;
import org.zkoss.bind.annotation.Init;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.OpenEvent;
import org.zkoss.zk.ui.select.annotation.VariableResolver;
import org.zkoss.zk.ui.select.annotation.WireVariable;
import org.zkoss.zkplus.spring.DelegatingVariableResolver;
import org.zkoss.zul.DefaultTreeModel;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.TreeModel;
import org.zkoss.zul.TreeNode;
import org.zkoss.zul.Window;

import vn.smartoffice.auth.UserService;
import vn.smartoffice.promail.dto.MailFolderNode;
import vn.smartoffice.promail.entity.MailFolder;
import vn.smartoffice.promail.services.MailFolderService;
import vn.smartoffice.promail.services.MailItemService;

@VariableResolver(DelegatingVariableResolver.class)
public class MailFolderCtr {

	@WireVariable private MailFolderService mailFolderService;
	@WireVariable private MailItemService mailItemService;
	@WireVariable private UserService userService;

	@Getter @Setter private MailFolderNode selectedNode;
	private MailFolderNode rootNode;

	public TreeModel<TreeNode<MailFolder>> getData() {
		return createTreeFolderModel();
	}

	@Init
	public void init() {
		DefaultTreeModel<MailFolder> treeModel = createTreeFolderModel();
		selectedNode = (MailFolderNode) treeModel.getChild(rootNode, 0);
	}

	@Command("createFolder")
	public void createFolder() {
		Map<String, Object> dataArgs = new HashMap<>();
		if (selectedNode != null) {
			dataArgs.put("node", selectedNode);
		} else {
			dataArgs.put("node", rootNode);
		}
		dataArgs.put("isCreateFolder", true);
		Window window = (Window) Executions.createComponents("dialog/folder.zul", null, dataArgs);
		window.doModal();
	}

	@Command("renameFolder")
	public void renameFolder() {
		HashMap<String, Object> dataArgs = new HashMap<>();
		dataArgs.put("node", selectedNode);
		dataArgs.put("isCreateFolder", false);
		Window window = (Window) Executions.createComponents("dialog/folder.zul", null, dataArgs);
		window.doModal();
	}

	@Command("deleteFolder")
	@NotifyChange({ "data", "selectedNode" })
	public void deleteFolder() {
		if (selectedNode.getParentId() != null) {
			Messagebox.show(Labels.getLabel("delete.messages"), Labels.getLabel("delete.title"), Messagebox.OK
					| Messagebox.CANCEL, Messagebox.QUESTION, new EventListener<Event>() {
				@Override
				public void onEvent(Event event) throws Exception {
					if (event.getName().equals("onOK")) {
						MailFolderNode parentNode = (MailFolderNode) selectedNode.getParent();
						mailFolderService.deleteById(selectedNode.getId());
						selectedNode = parentNode;
						BindUtils.postNotifyChange(null, null, MailFolderCtr.this, "selectedNode");
						BindUtils.postNotifyChange(null, null, MailFolderCtr.this, "data");
						Map<String, Object> args = new HashMap<String, Object>();
						args.put("base", parentNode);
						BindUtils.postGlobalCommand(null, null, "showMailItemList", args);
						getData();

					}
				}
			});
		} else {
			Messagebox.show(Labels.getLabel("macdinh.errorMessages"), Labels.getLabel("wraning.title"), Messagebox.OK,
					Messagebox.EXCLAMATION);
		}
	}

	@Command("setOpen")
	@NotifyChange("data")
	public void setOpen(@ContextParam(ContextType.BIND_CONTEXT) BindContext ctx,
			@BindingParam("item") MailFolderNode item) {
		OpenEvent event = (OpenEvent) ctx.getTriggerEvent();
		item.getData().setOpen(event.isOpen());
		if (!event.isOpen()) {
			closeNode(item);
		}
		mailFolderService.update(item.getData());

	}

	@Command("dropToNode")
	@NotifyChange("data")
	public void dropToNode(@BindingParam("item") MailFolderNode item, @BindingParam("base") MailFolderNode base) {
		if (item != null && base != null && item.getParent() != base) {
			addNode(base, item);
		}
	}

	@GlobalCommand
	@NotifyChange("data")
	public void refreshMailFolder() {
	}

	private void closeNode(MailFolderNode node) {
		if (node.getChildren().isEmpty()) {
			node.getData().setOpen(false);
			mailFolderService.update(node.getData());
		} else {
			for (MailFolderNode mailFolderNode : node.getChildrenNode()) {
				closeNode(mailFolderNode);
			}
			node.getData().setOpen(false);
			mailFolderService.update(node.getData());
		}
	}

	private void addNode(MailFolderNode parentNode, MailFolderNode childNode) {
		parentNode.add(childNode);
		MailFolder mailFolder = childNode.getData();
		mailFolder.setParentId(parentNode.getId());
		mailFolderService.update(mailFolder);
	}

	private MailFolderNode findById(List<MailFolderNode> mailFolderNodes, long id) {
		for (MailFolderNode mailFolderNode : mailFolderNodes) {
			if (mailFolderNode.getId() == id) {
				return mailFolderNode;
			}
		}
		return null;
	}

	private List<MailFolderNode> createListNode(List<MailFolder> mailFolders) {
		List<MailFolderNode> listNode = new ArrayList<MailFolderNode>();
		for (MailFolder mailFolder : mailFolders) {
			listNode.add(new MailFolderNode(mailFolder));
		}
		return listNode;
	}

	private MailFolderNode createRootNode(List<MailFolderNode> listNode) {
		MailFolderNode rootNode = new MailFolderNode(null);
		for (MailFolderNode mailFolderNode : listNode) {
			if (mailFolderNode.getParentId() == null) {
				rootNode.add(mailFolderNode);
			} else {
				findById(listNode, mailFolderNode.getParentId()).add(mailFolderNode);
			}
		}
		return rootNode;
	}

	private DefaultTreeModel<MailFolder> createTreeFolderModel() {
		List<MailFolder> mailFolders = mailFolderService.findByUserId(userService.getCurrentUserId());
		rootNode = createRootNode(createListNode(mailFolders));
		DefaultTreeModel<MailFolder> treeModel = new DefaultTreeModel<>(rootNode);
		return treeModel;
	}

}
